#include "stdafx.h"
#include "XUIThreadProcImpl.h"

#include "IntSkinImpl.h"

IMPLEMENT_SKIN_CLASS(CXUIThreadProcImpl);

#define UI_THREAD_PROC_CLASS_NAME _T("UIThreadWnd")
#define UI_THREAD_PROC_OBJ_PROP_NAME _T("UIProcObj")

CXUIThreadProcImpl::CXUIThreadProcImpl()
{
    m_xSyncWnd = NULL;
    m_nUIThreadAddTaskMsgId = 0;
}
CXUIThreadProcImpl::~CXUIThreadProcImpl()
{
}

//////////////////////////////////////////////////////////////////////////

// IXUIThreadProc
HRESULT CXUIThreadProcImpl::PostUIThreadProc(UIProcFunc func, LPARAM lParam)
{
    if(func == NULL)
        return E_INVALIDARG;

    if(!NeedSyncWnd())
        return E_FAIL;

    stUIProcInfo* pInfo = new stUIProcInfo;
    pInfo->Func = func;
    pInfo->lParam = lParam;

    BOOL bResult = ::PostMessage((HWND)m_xSyncWnd, m_nUIThreadAddTaskMsgId, (WPARAM)pInfo, (LPARAM)0);

    return bResult ? S_OK : E_FAIL;
}

HRESULT CXUIThreadProcImpl::SendUIThreadProc(UIProcFunc func, LPARAM lParam)
{
    if(func == NULL)
        return E_INVALIDARG;

    if(!NeedSyncWnd())
        return E_FAIL;

    stUIProcInfo* pInfo = new stUIProcInfo;
    pInfo->Func = func;
    pInfo->lParam = lParam;

    BOOL bResult = ::SendMessage((HWND)m_xSyncWnd, m_nUIThreadAddTaskMsgId, (WPARAM)pInfo, (LPARAM)0);

    return bResult ? S_OK : E_FAIL;
}

//////////////////////////////////////////////////////////////////////////
// IXBaseObj
void CXUIThreadProcImpl::OnFinalRelease()
{
    ReleaseData();
}

// CXUIThreadProcImpl
void CXUIThreadProcImpl::ReleaseData()
{
    DestroySyncWnd();
}

BOOL CXUIThreadProcImpl::NeedSyncWnd()
{
    if(m_xSyncWnd != NULL)
        return TRUE;

    m_nUIThreadAddTaskMsgId = ::RegisterWindowMessage(_T("UIProcAddTask"));

    m_xSyncWnd = IntSkinImpl::XCreateMessageWindow(UI_THREAD_PROC_CLASS_NAME, &CXUIThreadProcImpl::SyncWindowProc);
    if(m_xSyncWnd == NULL)
        return FALSE;

    ::SetWindowLongPtr((HWND)m_xSyncWnd, GWLP_USERDATA, (LONG)this);
    return TRUE;
}

void CXUIThreadProcImpl::DestroySyncWnd()
{
    if(m_xSyncWnd != NULL)
    {
        ::SetWindowLongPtr((HWND)m_xSyncWnd, GWLP_USERDATA, (LONG)NULL);
        ::DestroyWindow((HWND)m_xSyncWnd);

        m_xSyncWnd = NULL;
    }
}

LRESULT CXUIThreadProcImpl::SyncWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    CXUIThreadProcImpl* pThis = (CXUIThreadProcImpl*)::GetWindowLongPtr((HWND)hWnd, GWLP_USERDATA);
    if(pThis != NULL)
    {
        if(pThis->m_nUIThreadAddTaskMsgId == message)
        {
            stUIProcInfo* pInfo = (stUIProcInfo*)wParam;
            if(pInfo != NULL)
            {
                (*(pInfo->Func))(pInfo->lParam);
                delete pInfo;
            }
        }
    }

    return ::DefWindowProc(hWnd, message, wParam, lParam);
}

